
/*
 Filament释放姿势备忘：
 全局的
    (Engine *)->destroy(Renderer *);
    (Engine *)->destroy(Scene *);
    (Engine *)->destroy(View *);
    (Engine *)->destroy(Camera *);
    (Engine *)->destroy(SwapChain *);
    (Engine *)->destroy(engine);
 
 如果用了GLB模型 (这里Entity的释放不用我们主动去destroy了)
    (gltfio::AssetLoader *)->destroy(gltfio::FilamentAsset *)
    gltfio::AssetLoader::destroy(gltfio::AssetLoader *)
 
 如果用了IBL
    (Engine *)->destroy(IndirectLight *);
    (Engine *)->destroy(Texture *);
    image::KtxBundle 指针虽是new出来的，但是其内部会自动帮我们释放

 如果加了Sun
    Sun和普通的Entity一样，参考下面的【销毁 Entity 的姿势】
 
 销毁 Entity 的姿势
    (Scene *)->remove(entity);
    (Engine *)->destroy(entity);
    (Engine *)->getTransformManager().destroy(entity);
    EntityManager::get().destroy(1, &entity);
 */
#import "FilamentRender.h"

#import <filament/Renderer.h>
#import <filament/Scene.h>
#import <filament/Engine.h>
#import <filament/SwapChain.h>
#import <filament/RenderTarget.h>
#import <filament/View.h>
#import <filament/Viewport.h>
#import <filament/RenderableManager.h>
#import <filament/TransformManager.h>
#import <filameshio/MeshReader.h>
#import <filament/LightManager.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/Animator.h>
#include <gltfio/AssetLoader.h>

#include <gltfio/FilamentAsset.h>
#include <gltfio/MaterialProvider.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/SimpleViewer.h>
#import <utils/EntityManager.h>

#import "YYWeakProxy.h"
using namespace filament;
using namespace filamesh;

using utils::Entity;
using utils::EntityManager;
using filament::Engine;
@implementation FilamentRender {
	Engine *_engine;
	SwapChain *_swapChain;
    Renderer* _renderer;
    View *_filaView;
    Camera *_camera;
    void *_nativeLayer;
	CADisplayLink* _displayLink;
    void (^_perFrameCallback)(void);
}

- (void)removeEntity:(utils::Entity)entity{
    if (!entity.isNull()) {
        _scene->remove(entity);
        _engine->destroy(entity);
        _engine->getTransformManager().destroy(entity);
        EntityManager::get().destroy(entity);
    }
}

- (void)removeEntitys:(utils::Entity *)entity count:(NSInteger)count{
    for (int i = 0; i < count; i++) {
        _scene->remove(*(entity + i));
        _engine->destroy(*(entity + i));
        _engine->getTransformManager().destroy(*(entity + i));
    }
    EntityManager::get().destroy(count, entity);
}

- (void)dealloc{
    _engine->destroy(_renderer);
	_engine->destroy(_scene);
	_engine->destroy(_filaView);
	_engine->destroy(_camera);
	_engine->destroy(_swapChain);
	_engine->destroy(_engine);
}

- (instancetype)initWithViewPort:(CGRect)viewPort
					 nativeLayer:(void *)nativeLayer{
    self = [super init];
    if (self) {
        _nativeLayer = nativeLayer;
        _viewPort = viewPort;
        
        //跟踪用户创建的所有资源、管理渲染线程以及硬件渲染器
        _engine = Engine::create(filament::Engine::Backend::METAL);
		
        //SwapChain 表示不同操作系统的 renderable surface
        _swapChain = _engine->createSwapChain(_nativeLayer, SwapChain::CONFIG_TRANSPARENT);
        
        //Render会为渲染线程生成绘制命令同时负责管理帧。
        _renderer = _engine->createRenderer();
		
        //Scene 是物体和光源的容器。可以在任何时刻给场景添加或删除物体。
        _scene = _engine->createScene();
        
        _camera = _engine->createCamera();
        
		//View 包含了渲染场景所需的所有状态
        _filaView = _engine->createView();
        _filaView->setScene(_scene);
        _filaView->setCamera(_camera);
        _filaView->setViewport(Viewport(_viewPort.origin.x,
										_viewPort.origin.y,
										_viewPort.size.width,
										_viewPort.size.height)
							   );
//      _filaView->setSampleCount(4);
        _filaView->setClearColor({0.0f, 0.0f, 0.0f, 0.0f});
        
		_displayLink = [CADisplayLink displayLinkWithTarget: [YYWeakProxy proxyWithTarget:self] selector:@selector(frameCallback)];
		[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
		[_displayLink setPaused:YES];
        
    }
    return self;
}

- (void)frameCallback{
	[self doRenderOnce];
    if (_perFrameCallback) {
        _perFrameCallback();
    }
}

- (void)setViewPort:(CGRect)viewPort{
    _viewPort = viewPort;
    _filaView->setViewport(Viewport(_viewPort.origin.x,
									_viewPort.origin.y,
									_viewPort.size.width,
									_viewPort.size.height)
						   );
}

- (void)startLoopRenderWithPerFrameCallback:(void(^)(void))perFrameCallback{
    _perFrameCallback = perFrameCallback;
	[_displayLink setPaused:NO];
}

- (void)stopLoopRender{
	[_displayLink setPaused:YES];
}

- (void)doRenderOnce{
    //管理帧的渲染节奏。比如GPU渲染比较慢的时候（而cpu又比较快的计算出要渲染的数据），就会返回false，然后让外部跳过帧，这样就不至于延迟cpu太多。
	if (_renderer->beginFrame(_swapChain)) {
        //filament 的主渲染函数，cpu侧的一些任务都在这里执行，该函数会生成渲染命令交给渲染线程去执行。
		_renderer->render(_filaView);
        //渲染完毕，告诉render backend上屏
		_renderer->endFrame();
	}
}
@end
